﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Serialization;
using ButsaScraperLib;

namespace TeamCompare
{
	/// <summary>
	/// Interaction logic for TeamParams.xaml
	/// </summary>
	public partial class TeamParams : UserControl
	{
		private Team _team = null;

		/// <summary>
		/// 
		/// </summary>
		private double[][] _coeff = { 
			//				 Ld,Rd	 Cd		Lwd,Rwd	Dm		Lm,Rm	Cm		Lw,Rw	Am		Lf,Rf	Cf
			new	double[]	{ 1.0,	1.0,	1.0,	0.8,	0.8,	0.7,	0.6,	0.6,	0.6,	0.6	}, // отбор
			new	double[]	{ 1.0,	1.0,	1.0,	0.8,	0.8,	0.7,	0.6,	0.6,	0.6,	0.6	}, // опека
			new	double[]	{ 0.6,	0.6,	0.6,	0.6,	1.0,	0.7,	1.0,	0.8,	0.8,	1.0	}, // дриблинг
			new	double[]	{ 0.4,	0.6,	0.6,	1.0,	1.0,	1.0,	1.0,	0.8,	1.0,	1.0	}, // прием мяча
			new	double[]	{ 0.8,	0.8,	0.8,	0.8,	1.0,	1.0,	1.0,	1.0,	0.8,	0.6	}, // пас
			new	double[]	{ 0.4,	0.6,	0.4,	0.4,	0.6,	0.6,	0.8,	0.8,	0.8,	1.0	}, // сила удара
			new	double[]	{ 0.4,	0.6,	0.4,	0.4,	0.6,	0.6,	0.8,	0.8,	0.8,	1.0	}, // точность удара
			new	double[]	{ 1.0,	1.0,	1.0,	1.0,	1.0,	1.0,	1.0,	1.0,	1.0,	1.0	}  //выносливость
		};

		public TeamParams()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Пользователь ввёл код команды.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void SelfLabeledTextBoxKeyUp(object sender, KeyEventArgs e)
		{
			if (e.Key == Key.Enter)
			{
				_team = ButsaManager.Instance.GetTeamById(TeamCodeInputBox.Text.Trim());
				if (_team != null)
				{
					TeamNameTextBlock.Text = _team.TeamName;
					DivisionTextBlock.Text = _team.DivisionName;
					ManagerTextBlock.Text = _team.Manager;
					MoneyTextBlock.Text = _team.Money;
					ViewRatingTextBlock.Text = _team.Rating.ToString("0.0#");
					PlayersCountTextBlock.Text = _team.Players.Count.ToString();
					TeamPowerTextBlock.Text = _team.Force.ToString("0.0#");
					TeamPower11TextBlock.Text = _team.Top11Force.ToString("0.0#");
					AttackProfileTextBlock.Text = CalculateAttackProfile(_team).ToString("0.0#");
					DefenceProfileTextBlock.Text = CalculateDefenceProfile(_team).ToString("0.0#");
				}
				else
				{
					//TODO: wrong code or other error message
				}
			}
		}

		/// <summary>
		/// 	Cf		Lf,Rf	Am
		///СУ	1.00	0.80	0.80
		///ТУ	1.00	0.80	0.80
		///Пс	0.60	0.80	1.00
		///Пр	1.00	1.00	0.80
		///Др	1.00	0.80	0.80
		///Оп	0.60	0.60	0.60
		///От	0.60	0.60	0.60
		///Вн	1.00	1.00	1.00
		/// </summary>
		/// <param name="team"></param>
		/// <returns></returns>
		private double CalculateAttackProfile(Team team)
		{
			//Cf
			var skills = team.Players
				.Where(player => (player.PrimaryPosition == Position.Cf || player.PrimaryPosition == Position.Lf ||
					player.PrimaryPosition == Position.Rf || player.SecondaryPosition == Position.Cf ||
					player.SecondaryPosition == Position.Lf || player.SecondaryPosition == Position.Rf || 
					player.SecondaryPosition == Position.Am)
					&& !player.IsTraumed && !player.IsDiscvalificated)
				.Distinct()
				.Select(player => ForwardCalculation(player) * player.PhysicalFitness / 100.0)
				.ToArray();
			return Percentel75Inc(skills);
		}

		private double CalculateDefenceProfile(Team team)
		{
			//+учитывать Бонусы
			//всё, кроме точности, силы удара или дриблинга
			var skills = team.Players
				.Where(player => (player.PrimaryPosition == Position.Cd || player.PrimaryPosition == Position.Ld ||
					player.PrimaryPosition == Position.Rd || player.SecondaryPosition == Position.Cd ||
					player.SecondaryPosition == Position.Ld || player.SecondaryPosition == Position.Rd || player.SecondaryPosition == Position.Dm) &&
					!player.IsTraumed && !player.IsDiscvalificated)
				.Distinct()
				.Select(player => (player.MarkingSkill + player.TakingSkill + player.ReceptionSkill + 
					player.PassSkill + player.StaminaSkill) * player.PhysicalFitness / 100.0)
				.ToArray();
			return Percentel75Inc(skills) / (6 * 26.0);
		}

		private double Percentel75Inc(double[] values)
		{
			int startIndex = (int)(values.Length * 0.75) - 1;
			Array.Sort(values);
			double percentel = 0;
			for (int i = startIndex; i < values.Length; i++)
			{
				percentel += values[i];
			}
			percentel /= (values.Length - startIndex);
			return percentel;
		}

		/// <summary>
		/// 	Cf		Lf,Rf	Am
		///СУ	1.00	0.80	0.80
		///ТУ	1.00	0.80	0.80
		///Пс	0.60	0.80	1.00
		///Пр	1.00	1.00	0.80
		///Др	1.00	0.80	0.80
		///Оп	0.60	0.60	0.60
		///От	0.60	0.60	0.60
		///Вн	1.00	1.00	1.00
		///(3*max + 1*min) / 4
		/// </summary>
		/// <param name="player"></param>
		/// <returns></returns>
		private double ForwardCalculation(Player player)
		{
			double[][] coeff = { 
								   new double[] {1.0,	0.8,	0.8},
								   new double[] {1.0,	0.8,	0.8},
								   new double[] {0.6,	0.8,	1.0},
								   new double[] {1.0,	1.0,	0.8},
								   new double[] {1.0,	0.8,	0.8},
								   new double[] {0.6,	0.6,	0.6},
								   new double[] {0.6,	0.6,	0.6},
								   new double[] {1.0,	1.0,	1.0}
							   };
			 
			//выбор позиций
			int k1 = -1, k2 = -1;
			if (player.PrimaryPosition == Position.Cf)
				k1 = 0;
			else if (player.PrimaryPosition == Position.Rf || player.PrimaryPosition == Position.Lf)
				k1 = 1;
			else if (player.PrimaryPosition == Position.Am)
				k1 = 2;

			if (player.SecondaryPosition.HasValue)
			{
				if (player.SecondaryPosition == Position.Cf)
					k2 = 0;
				else if (player.SecondaryPosition == Position.Rf || player.SecondaryPosition == Position.Lf)
					k2 = 1;
				else if (player.SecondaryPosition == Position.Am)
					k2 = 2;
				else
					k2 = k1;
			}
			else
				k2 = k1;

			//если первое совмещение не атакующее
			if (k1 == -1)
				k1 = k2;

			double strikePower = player.StrikeValueSkill * 
				(3 * Math.Max(coeff[0][k1], coeff[0][k2]) + Math.Min(coeff[0][k1], coeff[0][k2])) / 4.0;
			double strikeAccuracy = player.StrikeAccuracySkill * 
				(3 * Math.Max(coeff[1][k1], coeff[1][k2]) + Math.Min(coeff[1][k1], coeff[1][k2])) / 4.0;
			double pass = player.PassSkill *
				(3 * Math.Max(coeff[2][k1], coeff[2][k2]) + Math.Min(coeff[2][k1], coeff[2][k2])) / 4.0;
			double reception = player.ReceptionSkill *
				(3 * Math.Max(coeff[3][k1], coeff[3][k2]) + Math.Min(coeff[3][k1], coeff[3][k2])) / 4.0;
			double dribbling = player.DribblingSkill * 
				(3 * Math.Max(coeff[4][k1], coeff[4][k2]) + Math.Min(coeff[4][k1], coeff[4][k2])) / 4.0;
			double marking = player.MarkingSkill *
				(3 * Math.Max(coeff[5][k1], coeff[5][k2]) + Math.Min(coeff[5][k1], coeff[5][k2])) / 4.0;
			double taking = player.TakingSkill * 
				(3 * Math.Max(coeff[6][k1], coeff[6][k2]) + Math.Min(coeff[6][k1], coeff[6][k2])) / 4.0;
			double stamina = player.StaminaSkill * 
				(3 * Math.Max(coeff[7][k1], coeff[7][k2]) + Math.Min(coeff[7][k1], coeff[7][k2])) / 4.0;

			return strikePower + strikeAccuracy + pass + reception + dribbling + marking + taking + stamina;
		}

		private double DefenderCalculation(Player player)
		{
			//в строках умения, в столбцах - Ld Rd Cd Lwd Rwd Dm

			double[][] coeff = {
								   new double[] {1.0,	0.8,	0.8}, // отбор
								   new double[] {1.0,	0.8,	0.8}, // опека
								   new double[] {0.6,	0.8,	1.0}, // дриблинг
								   new double[] {1.0,	1.0,	0.8}, // прием мяча
								   new double[] {1.0,	0.8,	0.8}, // пас
								   new double[] {0.6,	0.6,	0.6}, // сила удара
								   new double[] {0.6,	0.6,	0.6}, // точность удара
								   new double[] {1.0,	1.0,	1.0}  //выносливость
							   };

			//выбор позиций
			int k1 = -1, k2 = -1;
			if (player.PrimaryPosition == Position.Cf)
				k1 = 0;
			else if (player.PrimaryPosition == Position.Rf || player.PrimaryPosition == Position.Lf)
				k1 = 1;
			else if (player.PrimaryPosition == Position.Am)
				k1 = 2;

			if (player.SecondaryPosition.HasValue)
			{
				if (player.SecondaryPosition == Position.Cf)
					k2 = 0;
				else if (player.SecondaryPosition == Position.Rf || player.SecondaryPosition == Position.Lf)
					k2 = 1;
				else if (player.SecondaryPosition == Position.Am)
					k2 = 2;
				else
					k2 = k1;
			}
			else
				k2 = k1;

			//если первое совмещение не атакующее
			if (k1 == -1)
				k1 = k2;

			double strikePower = player.StrikeValueSkill *
				(3 * Math.Max(coeff[0][k1], coeff[0][k2]) + Math.Min(coeff[0][k1], coeff[0][k2])) / 4.0;
			double strikeAccuracy = player.StrikeAccuracySkill *
				(3 * Math.Max(coeff[1][k1], coeff[1][k2]) + Math.Min(coeff[1][k1], coeff[1][k2])) / 4.0;
			double pass = player.PassSkill *
				(3 * Math.Max(coeff[2][k1], coeff[2][k2]) + Math.Min(coeff[2][k1], coeff[2][k2])) / 4.0;
			double reception = player.ReceptionSkill *
				(3 * Math.Max(coeff[3][k1], coeff[3][k2]) + Math.Min(coeff[3][k1], coeff[3][k2])) / 4.0;
			double dribbling = player.DribblingSkill *
				(3 * Math.Max(coeff[4][k1], coeff[4][k2]) + Math.Min(coeff[4][k1], coeff[4][k2])) / 4.0;
			double marking = player.MarkingSkill *
				(3 * Math.Max(coeff[5][k1], coeff[5][k2]) + Math.Min(coeff[5][k1], coeff[5][k2])) / 4.0;
			double taking = player.TakingSkill *
				(3 * Math.Max(coeff[6][k1], coeff[6][k2]) + Math.Min(coeff[6][k1], coeff[6][k2])) / 4.0;
			double stamina = player.StaminaSkill *
				(3 * Math.Max(coeff[7][k1], coeff[7][k2]) + Math.Min(coeff[7][k1], coeff[7][k2])) / 4.0;

			return strikePower + strikeAccuracy + pass + reception + dribbling + marking + taking + stamina;
		}


		private void ToXmlButtonClick(object sender, RoutedEventArgs e)
		{
			MemoryStream memoryStream = new MemoryStream();
			new XmlSerializer(typeof(Team)).Serialize(memoryStream, _team);

			memoryStream.Position = 0;
			byte[] data = new byte[memoryStream.Length];
			memoryStream.Read(data, 0, data.Length);
			File.WriteAllBytes("team.txt", data);
		}
	}

	//Отбор – увеличивает вероятность отбора мяча
	//Опека – увеличивает вероятность опеки игрока соперника
	//Дриблинг – увеличивает вероятность обыграть защитника соперника
	//Примем мяча – увеличивает вероятность приема мяча
	//Выносливость – уменьшает потери ф/г
	//Пас – увеличивает вероятность точного паса
	//Сила - влияет на дальность и скорость ударов/пасов - опять же быстрый мяч сложней поймать/отбить (вратарю)
	//Точность - влияет на точность удара и паса.

}
